/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package test.shanika;

import com.googlecode.javacpp.Loader;
import com.googlecode.javacv.CanvasFrame;
import com.googlecode.javacv.FrameGrabber;
import com.googlecode.javacv.FrameGrabber.Exception;
import com.googlecode.javacv.OpenCVFrameGrabber;
import com.googlecode.javacv.VideoInputFrameGrabber;
import com.googlecode.javacv.cpp.opencv_calib3d.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import com.googlecode.javacv.cpp.opencv_calib3d.*;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import static com.googlecode.javacv.cpp.opencv_imgproc.*;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author HOME
 */
public class HSVThreshold {

    CvMemStorage storage = CvMemStorage.create();
    CvSeq hull;
    CanvasFrame hueI = new CanvasFrame("Hue");
    CanvasFrame hand = new CanvasFrame("Hand");
    private CvScalar hsv_min = cvScalar(6, 45, 0, 0);
    private CvScalar hsv_max = cvScalar(50, 255, 255, 0);

    public static void main(String[] args) {

        CanvasFrame orgcan = new CanvasFrame("Original Image");

        HSVThreshold bg = new HSVThreshold();
        FrameGrabber grabber = new VideoInputFrameGrabber(2);
        //     FrameGrabber grabber=new OpenCVFrameGrabber("resources/fypVid1.avi");
        try {

            grabber.start();
            Thread.sleep(500);
            while (true) {
                IplImage image = grabber.grab();

                bg.fingerDetect(image);
                orgcan.showImage(image);
            }
        } catch (InterruptedException ex) {
            Logger.getLogger(HSVThreshold.class.getName()).log(Level.SEVERE, null, ex);
        } catch (Exception ex) {
            Logger.getLogger(HSVThreshold.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void fingerDetect(IplImage image) {
        //  int vmin = 1, vmax = 256, smin = 45;

        IplImage hsvImage = cvCreateImage(image.cvSize(), image.depth(), 3);
        //      IplImage masks = cvCreateImage(image.cvSize(), 8, 1);
        cvCvtColor(image, hsvImage, CV_BGR2HSV);
        //    cvInRangeS(hsvImage, cvScalar(0, smin, Math.min(vmin,vmax), 0), cvScalar(180, 256, Math.max(vmin, vmax), 0), masks);

        // Split the 3 channels into 3 images
        IplImageArray hsvChannels = splitChannels(hsvImage);

        //bins and value-range
        int numberOfBins = 50; // should be changed
        float minRange = 1f;
        float maxRange = 50f;

        // Allocate histogram object
        int dims = 1;
        int[] sizes = new int[]{numberOfBins};
        int histType = CV_HIST_ARRAY;
        float[] minMax = new float[]{minRange, maxRange};
        float[][] ranges = new float[][]{minMax};
        int uniform = 1;

        CvHistogram hist = cvCreateHist(dims, sizes, histType, ranges, uniform);

        // Compute histogram
        int accumulate = 1;
        IplImage mask = null;
//        cvCalcHist(hsvChannels.position(0), hist, accumulate, null);

        // Normalize the Histogram

        //   cvNormalizeHist(hist, 100);


        /// Get Backprojection
        IplImage hue = hsvChannels.get();
        IplImage backproject = cvCreateImage(hue.cvSize(), 8, 1);
        IplImage suppImage = cvCreateImage(hue.cvSize(), 8, 1);

        hueI.showImage(hue);




        //cvCalcBackProject(hsvChannels.position(0), backproject, hist);

        cvReleaseHist(hist);

        cvThreshold(hue, suppImage, 160, 255, CV_THRESH_BINARY);

        IplConvKernel se = cvCreateStructuringElementEx(3, 3, 1, 1, CV_SHAPE_ELLIPSE, null); // Struncturing Element
        IplConvKernel se1 = cvCreateStructuringElementEx(5, 5, 3, 3, CV_SHAPE_ELLIPSE, null); // Struncturing Element

        cvMorphologyEx(suppImage, suppImage, suppImage, se1, CV_MOP_CLOSE, 1);
     //   cvMorphologyEx(suppImage, suppImage, suppImage, se1, CV_MOP_OPEN, 1);

        cvSmooth(suppImage, suppImage, CV_MEDIAN, 5);
        hand.showImage(suppImage);

        cvReleaseImage(backproject);
        cvReleaseImage(hue);


        extractContours(suppImage, image);
    }

    private IplImageArray splitChannels(IplImage hsvImage) {
        CvSize size = hsvImage.cvSize();
        int depth = hsvImage.depth();
        IplImage channel0 = cvCreateImage(size, depth, 1);
        IplImage channel1 = cvCreateImage(size, depth, 1);
        IplImage channel2 = cvCreateImage(size, depth, 1);
        //   hueI.showImage(channel0);
        cvSplit(hsvImage, channel0, channel1, channel2, null);
        return new IplImageArray(channel0, channel1, channel2);
    }

    private void extractContours(IplImage skin, IplImage img) {
        double result1 = 0;
        double largest = 0;
        double secondlargest = 0;
        CvSeq largestcontour = new CvSeq(null);
        CvSeq secondlargestcontour = new CvSeq(null);
        CvSeq contours = new CvSeq(null);


        int a = cvFindContours(skin, storage, contours, Loader.sizeof(CvContour.class), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE);

        if (a != 0) {
            while (contours != null) {
                //   result1 = contours.total();
                result1 = cvContourArea(contours, CV_WHOLE_SEQ, 0);
                if (result1 > largest) {
//                secondlargest = largest;
                    largest = result1;
                    largestcontour = contours;
                }
//            if (secondlargest < result1 && largest != result1) {
//                secondlargest = result1;
//                secondlargestcontour = contours;
//            }
                contours = contours.h_next();
            }

            if (largestcontour != null) {

                cvDrawContours(img, largestcontour, CvScalar.MAGENTA, CvScalar.WHITE, -1, 1, CV_FLOODFILL_MASK_ONLY);

                hull = cvConvexHull2(largestcontour, storage, CV_COUNTER_CLOCKWISE, 1);
                largest = 0;
                CvPoint v1 = null;
                for (int i = 0; i < hull.total(); i++) {

                    CvPoint v = new CvPoint(cvGetSeqElem(hull, i));

                    result1 = v.y();
                    if (result1 > largest) {
                        largest = result1;
                        v1 = v;
                    }

                }
                cvDrawCircle(img, v1, 5, CvScalar.RED, -1, 8, 0);

                System.out.println(" X value = " + v1.x() + " ; Y value =" + v1.y());
                cvClearSeq(hull);
                cvClearSeq(largestcontour);
            }

            cvClearMemStorage(storage);

        }
    }
}
